﻿using System;
using System.ComponentModel;
using System.Data.Linq;
using System.Data.Linq.Mapping;

namespace WeatherService
{
    [Table]
    public class City : INotifyPropertyChanged,INotifyPropertyChanging
    {
        #region Properties

        #region Id Property(Database)
        // Define ID: private field, public property, and database column.
        private int _id;

        [Column(DbType = "INT NOT NULL IDENTITY", IsDbGenerated = true, IsPrimaryKey = true)]
        public int Id
        {
            get { return _id; }
            set
            {
                NotifyPropertyChanging("Id");
                _id = value;
                NotifyPropertyChanged("Id");
            }
        }
        #endregion

        #region CityCode Property
        // Define ID: private field, public property, and database column.
        private string _cityCode;

        [Column]
        public string CityCode
        {
            get { return _cityCode; }
            set
            {
                NotifyPropertyChanging("CityCode");
                _cityCode = value;
                NotifyPropertyChanged("CityCode");
            }
        }
        #endregion

        #region ChineseName Property
        // Define category name: private field, public property, and database column.
        private string _chineseName;

        [Column]
        public string ChineseName
        {
            get { return _chineseName; }
            set
            {
                NotifyPropertyChanging("ChineseName");
                _chineseName = value;
                NotifyPropertyChanged("ChineseName");
            }
        }
        #endregion

        #region ShortName Property
        private string _shortName;

        [Column]
        public string ShortName
        {
            get { return _shortName; }
            set
            {
                NotifyPropertyChanging("ShortName");
                _shortName = value;
                NotifyPropertyChanged("ShortName");
            }
        }
        #endregion

        #region Latitude Property
        private string _latitude;

        [Column]
        public string Latitude
        {
            get { return _latitude; }
            set
            {
                NotifyPropertyChanging("Latitude");
                _latitude = value;
                NotifyPropertyChanged("Latitude");
            }
        }
        #endregion

        #region Longitude Property
        private string _longitude;

        [Column]
        public string Longitude
        {
            get { return _longitude; }
            set
            {
                NotifyPropertyChanging("Longitude");
                _longitude = value;
                NotifyPropertyChanged("Longitude");
            }
        }
        #endregion

        #region IsParentCity Property
        private bool _IsParentCity;
        
        [Column]
        public bool IsParentCity
        {
            get { return _IsParentCity; }
            set
            {
                NotifyPropertyChanging("IsParentCity");
                _IsParentCity = value;
                NotifyPropertyChanged("IsParentCity");
            }
        }
        #endregion

        #region ParentCity Property
        [Column(CanBeNull = true)]
        internal int _parentCityId;

        // Entity reference, to identify the parent city "storage" table
        private EntityRef<City> _parentCity;

        // Association, to describe the relationship between this key and that "storage" table
        [Association(Storage = "_parentCity", ThisKey = "_parentCityId", OtherKey = "Id")]
        public City ParentCity
        {
            get { return _parentCity.Entity; }
            set
            {
                NotifyPropertyChanging("ParentCity");
                _parentCity.Entity = value;
                if (value != null)
                {
                    _parentCityId = value.Id;
                }
                NotifyPropertyChanged("ParentCity");
            }
        }
        #endregion

        #region ParentProvince Property
        [Column]
        internal int _provinceId;

        // Entity reference, to identify the parent province "storage" table
        private EntityRef<Province> _province;

        // Association, to describe the relationship between this key and that "storage" table
        [Association(Storage = "_province", ThisKey = "_provinceId", OtherKey = "Id", IsForeignKey = true)]
        public Province ParentProvince
        {
            get { return _province.Entity; }
            set
            {
                NotifyPropertyChanging("ParentProvince");
                _province.Entity = value;
                if (value != null)
                {
                    _provinceId = value.Id;
                }
                NotifyPropertyChanged("ParentProvince");
            }
        }
        #endregion

        //#region Version Property
        //// Version column aids update performance.
        //[Column(IsVersion = true)]
        //private Binary _version;
        //#endregion

        #endregion

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        // Used to notify that a property changed
        private void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        #endregion

        #region INotifyPropertyChanging Members

        public event PropertyChangingEventHandler PropertyChanging;

        // Used to notify that a property is about to change
        private void NotifyPropertyChanging(string propertyName)
        {
            if (PropertyChanging != null)
            {
                PropertyChanging(this, new PropertyChangingEventArgs(propertyName));
            }
        }

        #endregion
    }

    [Table]
    public class Province : INotifyPropertyChanged, INotifyPropertyChanging
    {
        #region Id Property(Database)
        // Define ID: private field, public property, and database column.
        private int _id;

        [Column(DbType = "INT NOT NULL IDENTITY", IsDbGenerated = true, IsPrimaryKey = true)]
        public int Id
        {
            get { return _id; }
            set
            {
                NotifyPropertyChanging("Id");
                _id = value;
                NotifyPropertyChanged("Id");
            }
        }
        #endregion

        #region ChineseName Property
        // Define category name: private field, public property, and database column.
        private string _chineseName;

        [Column]
        public string ChineseName
        {
            get { return _chineseName; }
            set
            {
                NotifyPropertyChanging("ChineseName");
                _chineseName = value;
                NotifyPropertyChanged("ChineseName");
            }
        }
        #endregion

        #region ShortName Property
        // Define category name: private field, public property, and database column.
        private string _shortName;

        [Column]
        public string ShortName
        {
            get { return _shortName; }
            set
            {
                NotifyPropertyChanging("ShortName");
                _shortName = value;
                NotifyPropertyChanged("ShortName");
            }
        }
        #endregion

        #region Cities Property
        // Define the entity set for the collection side of the relationship.
        private EntitySet<City> _cities;

        [Association(Storage = "_cities", OtherKey = "_provinceId", ThisKey = "Id")]
        public EntitySet<City> Cities
        {
            get { return this._cities; }
            set { this._cities.Assign(value); }
        }
        #endregion

        //#region Version Property
        //// Version column aids update performance.
        //[Column(IsVersion = true)]
        //private Binary _version;
        //#endregion

        // Assign handlers for the add and remove operations, respectively.
        public Province()
        {
            _cities = new EntitySet<City>(
                new Action<City>(this.attach_City),
                new Action<City>(this.detach_City)
                );
        }

        // Called during an add operation
        private void attach_City(City _city)
        {
            NotifyPropertyChanging("City");
            _city.ParentProvince = this;
        }

        // Called during a remove operation
        private void detach_City(City _city)
        {
            NotifyPropertyChanging("City");
            _city.ParentProvince = null;
        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        // Used to notify that a property changed
        private void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        #endregion

        #region INotifyPropertyChanging Members

        public event PropertyChangingEventHandler PropertyChanging;

        // Used to notify that a property is about to change
        private void NotifyPropertyChanging(string propertyName)
        {
            if (PropertyChanging != null)
            {
                PropertyChanging(this, new PropertyChangingEventArgs(propertyName));
            }
        }

        #endregion
    }
}
